importClass(android.widget.Toast);
importClass(android.view.Gravity);
require("./config.js")

// 全局变量定义
let toastCustom = null;
let view = null

// 分辨率 以竖屏标准看
let screenWidth = config.screenWidth
let screenHeight = config.screenHeight

// 数据map
let dataMap = {}

let commonStorage = storages.create("suyibk.cn" + config.commonScriptKey);
// 获取设备uuid
let deviceUUID = commonStorage.get('deviceUUID')
if (!deviceUUID) {
    // 安卓10及以上 取androidId   10以下 取IMEI
    try {
        // 安卓10及以上 取androidId   10以下 取IMEI
        deviceUUID = config.SDK_API_VERSION > 28 ? device.getAndroidId() : device.getIMEI()
        commonStorage.put("deviceUUID", deviceUUID)
    } catch (e) {
        // 权限不足时使用随机UUID
        deviceUUID = java.util.UUID.randomUUID().toString();
        commonStorage.put("deviceUUID", deviceUUID)
        console.warn("无法获取设备标识，使用随机UUID: " + deviceUUID);
    }
}


module.exports = {
	ocr(img, cpuThreadNum, useSlim){
		return ocr(img)
		if (typeof cpuThreadNum === 'undefined') cpuThreadNum = 4;
		if (typeof useSlim === 'undefined') useSlim = true;
		return paddle.ocr(img,cpuThreadNum,useSlim);
	},
	ocrDetect(img, cpuThreadNum, useSlim){
		return ocr.detect(img);
		if (typeof cpuThreadNum === 'undefined') cpuThreadNum = 4;
		if (typeof useSlim === 'undefined') useSlim = true;
		return paddle.ocr(img,cpuThreadNum,useSlim);
	},
    getDeviceUUID() {
        return deviceUUID;
    },

    toast(msg) {
        try {
            if (toastCustom) {
                toastCustom.cancel();
            }
            toastCustom = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
            toastCustom.setGravity(Gravity.CENTER, 0, 0);
            toastCustom.show();
        } catch (e) {
            console.error("toast error:", e);
        }
    },

    getMemoryInfo() {
        try {
            let memInfo = device.getMemoryInfo();
            let totalMem = memInfo.totalMem / 1024 / 1024; // MB
            let availMem = memInfo.availMem / 1024 / 1024; // MB
            let usedMem = totalMem - availMem;
            let memUsage = (usedMem / totalMem * 100).toFixed(2);
            
            return {
                totalMem: totalMem.toFixed(2),
                availMem: availMem.toFixed(2),
                usedMem: usedMem.toFixed(2),
                memUsage: memUsage
            };
        } catch (e) {
            console.error("getMemoryInfo error:", e);
            return null;
        }
    },

    clearMemory() {
        gc();
    },

    exitApp(appName, callback) {
        try {
            let packageName = app.getPackageName(appName);
            if (packageName) {
                // 尝试强制停止应用
                shell("am force-stop " + packageName, true);
                sleep(1000);
                
                // 检查应用是否还在运行
                let isRunning = currentPackage() === packageName;
                if (!isRunning) {
                    console.log("应用已成功退出: " + appName);
                    if (callback) callback(true);
                } else {
                    console.log("应用退出失败: " + appName);
                    if (callback) callback(false);
                }
            } else {
                console.log("未找到应用: " + appName);
                if (callback) callback(false);
            }
        } catch (e) {
            console.error("exitApp error:", e);
            if (callback) callback(false);
        }
    },

    sortByKey(array, key, order) {
        if (!array || !Array.isArray(array)) return array;
        
        return array.sort((a, b)=>{
            let aVal = a[key];
            let bVal = b[key];
            
            if (order === 'desc') {
                return bVal - aVal;
            } else {
                return aVal - bVal;
            }
        });
    },

    convertNumberToChart(numberVal) {
        if (typeof numberVal !== 'number') return numberVal;
        
        const chartMap = {
            '0': '零', '1': '一', '2': '二', '3': '三', '4': '四',
            '5': '五', '6': '六', '7': '七', '8': '八', '9': '九'
        };
        
        return numberVal.toString().split('').map(digit => chartMap[digit] || digit).join('');
    },

    convertChartToNumber(chartVal) {
        if (typeof chartVal !== 'string') return chartVal;
        
        const numberMap = {
            '零': '0', '一': '1', '二': '2', '三': '3', '四': '4',
            '五': '5', '六': '6', '七': '7', '八': '8', '九': '9'
        };
        
        let result = chartVal;
        for (let chart in numberMap) {
            result = result.replace(new RegExp(chart, 'g'), numberMap[chart]);
        }
        
        return isNaN(Number(result)) ? chartVal : Number(result);
    },

    includesContains(arr, val) {
        if (!Array.isArray(arr)) return false;
        
        return arr.some(item => {
            if (typeof item === 'string' && typeof val === 'string') {
                return item.includes(val);
            }
            return item === val;
        });
    },

    // 坐标转换
    convertXY(x, y, isTrue) {
        if (typeof isTrue === 'undefined') isTrue = true;
        if(isTrue){
            return {
                x: x,
                y: y
            }
        }
        let currentScreenWidth = device.width;
        let currentScreenHeight = device.height;
        
        let scaleX = currentScreenWidth / screenWidth;
        let scaleY = currentScreenHeight / screenHeight;
		console.log(`currentScreenWidth=${currentScreenWidth},currentScreenHeight=${currentScreenHeight}`);
		console.log(`screenWidth=${screenWidth},screenHeight=${screenHeight}`);
        
        let convertedX = Math.round(x * scaleX);
        let convertedY = Math.round(y * scaleY);
        
		console.log(`原坐标(${x}, ${y}) -> 转换后(${convertedX}, ${convertedY})`);
        
        return {
            x: convertedX,
            y: convertedY
        };
    },

    // 随机点击
    randomClick(x, y, randomNum, needConvertXy, isRoot) {
        randomNum = randomNum || 10;
        let randomX = x + random(-randomNum, randomNum);
        let randomY = y + random(-randomNum, randomNum);
        
        if (needConvertXy) {
            let converted = this.convertXY(randomX, randomY);
            randomX = converted.x;
            randomY = converted.y;
        }
        
        if (true) {
            Tap(randomX, randomY);
        } else {
            click(randomX, randomY);
        }
        
		console.log(`随机点击坐标(${randomX}, ${randomY})`);
    },

    // 随机长按
    randomLongClick(x, y, duration, randomNum, needConvertXy, isRoot) {
        randomNum = randomNum || 10;
        duration = duration || 1000;
        let randomX = x + random(-randomNum, randomNum);
        let randomY = y + random(-randomNum, randomNum);
        
        if (needConvertXy) {
            let converted = this.convertXY(randomX, randomY);
            randomX = converted.x;
            randomY = converted.y;
        }
        
        if (isRoot) {
            Press(randomX, randomY, duration);
        } else {
            longClick(randomX, randomY);
        }
        
		console.log(`随机长按坐标(${randomX}, ${randomY}), 时长: ${duration}ms`);
    },

    // 随机滑动
    randomSwipe(x1, y1, x2, y2, duration, randomNum, needConvertXy, isRoot) {
        randomNum = randomNum || 10;
        duration = duration || 1000;
        
        let randomX1 = x1 + random(-randomNum, randomNum);
        let randomY1 = y1 + random(-randomNum, randomNum);
        let randomX2 = x2 + random(-randomNum, randomNum);
        let randomY2 = y2 + random(-randomNum, randomNum);
        
        if (needConvertXy) {
            let converted1 = this.convertXY(randomX1, randomY1);
            let converted2 = this.convertXY(randomX2, randomY2);
            randomX1 = converted1.x;
            randomY1 = converted1.y;
            randomX2 = converted2.x;
            randomY2 = converted2.y;
        }
        
        if (isRoot) {
            Swipe(randomX1, randomY1, randomX2, randomY2, duration);
        } else {
            swipe(randomX1, randomY1, randomX2, randomY2, duration);
        }
        
		console.log(`随机滑动(${randomX1}, ${randomY1}) -> (${randomX2}, ${randomY2}), 时长: ${duration}ms`);
    },

    // HTTP请求
    request(url, requestMethod, requestBody, callback) {
        let contentType = requestMethod === "GET" ? "application/x-www-form-urlencoded" : 'application/json';
        http.request(config.httpBaseUrl + "/ajControl/" + url, {
            headers: {
                "deviceUUID": deviceUUID
            },
            method: requestMethod,
            contentType: contentType,
            body: requestBody
        }, callback);
    },

    // 上传文件到服务器
    uploadFileToServer(localPath, fileName, callback) {
        http.postMultipart(config.httpBaseUrl + "/attachmentInfo/uploadFileToAutoJs", {
            file: open(localPath),
            imageName: fileName
        }, null, (res, error)=>{
            if (!res) {
                console.error("上传文件到服务器错误", error);
                return;
            }
            let data = res.body.json();
            if (res) {
                if (callback) {
                    callback(config.httpBaseUrl + "/" + data.data);
                }
            } else {
                console.error("上传文件到服务器错误", error);
            }
        });
    },

    // 远程执行脚本
    remoteExecScript(scriptText) {
        try {
            scriptText = decodeURIComponent(scriptText);
			console.log("远程脚本内容：" + scriptText);
            eval(scriptText);
            console.log("远程执行脚本完成");
        } catch (error) {
            console.error("远程执行脚本错误：", error);
        }
    },

    // 远程上传日志到服务器
    remoteUploadLogToServer(logName) {
        let localPathName = "/sdcard/autoJsLog/" + logName;
        this.uploadFileToServer(localPathName, deviceUUID + "/" + logName, (remoteImageURL)=>{
			console.log("远程日志地址：" + remoteImageURL);
        });
    },

    // 图像灰度化和阈值化处理
    grayscaleAndThreshold(img, threshold, maxVal){
        if (threshold == null || threshold == undefined) {
            return images.copy(img);
        }
        // 先灰度化
        let newImg = images.grayscale(img);
        // 再阈值化
        let newimg2 = images.threshold(newImg, threshold, maxVal, 'BINARY');
        // 回收图片
        newImg.recycle();
        return newimg2;
    },

    // 灰度化、阈值化找图
    grayThresholdFindImg(bigImg, smallImg, threshold, maxVal, imgThreshold){
        // 大图 灰度化、阈值化 
        let bigImgAfter = module.exports.grayscaleAndThreshold(bigImg, threshold, maxVal);
		images.save(bigImgAfter, './bigImgAfter.png','png',100);
        // 小图 灰度化、阈值化 
        let smallImgAfter = module.exports.grayscaleAndThreshold(smallImg, threshold, maxVal);
		images.save(smallImgAfter, './smallImgAfter.png','png',100);
        // 设置默认找图相似度
        if (!imgThreshold) {
            imgThreshold = 0.9;
        }
        // 调用官方的找图方法
        let findResult = images.findImage(bigImgAfter, smallImgAfter, { threshold: imgThreshold });
        // 回收图片
        bigImgAfter.recycle();
        smallImgAfter.recycle();
        // 返回结果
        return findResult;
    },
    // 区域找图
    regionalFindImg(img, targetImg, x1, y1, x2, y2, threshold, maxVal, imgThreshold){
        // 坐标转换
        let xy1 = module.exports.convertXY(x1, y1);
        let xy2 = module.exports.convertXY(x2, y2);
        console.log('regionalFindImg', xy1);
        // 按照区域坐标裁剪大图
        let clipImg = images.clip(img, xy1["x"], xy1["y"], xy2["x"] - xy1["x"], xy2["y"] - xy1["y"]);
        // 调用灰度化阈值化找图 在大图中找小图
        let findResult = module.exports.grayThresholdFindImg(clipImg, targetImg, threshold, maxVal, imgThreshold);
        // 回收裁剪图片
        clipImg.recycle();
        // 返回基于大图的坐标
        return {
            "x": findResult ? (xy1["x"] + findResult["x"]) : -1,
            "y": findResult ? (xy1["y"] + findResult["y"]) : -1
        };
    },

    // 区域匹配模板
    regionalMatchTemplate(img, targetImg, x1, y1, x2, y2, threshold, maxVal, imgThreshold, matchingCount, transparentMask){
        // 坐标转换
        let xy1 = module.exports.convertXY(x1, y1);
        let xy2 = module.exports.convertXY(x2, y2);
        // 按照区域坐标裁剪大图
        let clipImg = images.clip(img, xy1["x"], xy1["y"], xy2["x"] - xy1["x"], xy2["y"] - xy1["y"]);

        // 获取灰度化阈值化后的图片
        let grayThresholdImg = module.exports.grayscaleAndThreshold(clipImg, threshold, maxVal);
        // 回收图片
        clipImg.recycle();

        files.createWithDirs("/sdcard/autoJsAfterImg/");
        // 临时图片路径 
        let tempImgPath = "/sdcard/autoJsAfterImg/tempImg" + new Date().getTime() + ".png";
        // 保存临时图片
        images.save(grayThresholdImg, tempImgPath, "png", 100);

        // 读取临时图片
        let tempImg = images.read(tempImgPath);

        // 调用匹配图片方法
        let matchingResult = images.matchTemplate(tempImg, targetImg, {
            threshold: imgThreshold,
            max: matchingCount,
            transparentMask: transparentMask
        });
        // 回收图片
        grayThresholdImg.recycle();
        tempImg.recycle();
        files.remove(tempImgPath);
        return matchingResult;
    },

    // 区域找圆
    regionalFindCircles(img, x1, y1, x2, y2, threshold, maxVal){
        // 坐标转换
        let xy1 = module.exports.convertXY(x1, y1);
        let xy2 = module.exports.convertXY(x2, y2);
        // 按照区域坐标裁剪大图
        let clipImg = images.clip(img, xy1["x"], xy1["y"], xy2["x"] - xy1["x"], xy2["y"] - xy1["y"]);
        // 灰度化、阈值化图片
        let imgAfter = module.exports.grayscaleAndThreshold(clipImg, threshold, maxVal);
        files.createWithDirs("/sdcard/autoJsAfterImg/");
        // 临时图片路径 
        let tempImgPath = "/sdcard/autoJsAfterImg/tempImg" + new Date().getTime() + ".png";
        // 保存临时图片
        images.save(imgAfter, tempImgPath, "png", 100);
        // 读取图片
        let tempImage = images.read(tempImgPath);
        // 灰度化
        let grayImg = images.grayscale(tempImage);
        imgAfter.recycle();
        // 灰度化图片
        let resultArr = images.findCircles(grayImg);
        tempImage.recycle();
        clipImg.recycle();
        grayImg.recycle();
        // 删除临时图片
        files.remove(tempImgPath);

        let returnResultArr = [];
        resultArr.forEach(item => {
            returnResultArr.push({
                x: Number(item.x) + Number(xy1["x"]),
                y: Number(item.y) + Number(xy1["y"]),
                radius: Number(item.radius).toFixed(2)
            });
        });
        // 返回找圆结果
        return returnResultArr;
    },

    // 生成裁剪图片并灰度化阈值化
    generateClipImgGrayThreshold(x1, y1, x2, y2, threshold, maxVal, isOpenThreshold){
        // 截全屏
        let img = captureScreen();
        // 裁剪区域部分
        let clipImg = images.clip(img, x1, y1, x2 - x1, y2 - y1);
        if (!isOpenThreshold) {
            // 回收全屏图片
            img.recycle();
            // 返回裁剪图片
            return clipImg;
        } else {
            // 灰度化、阈值化图片
            let handlerImg = module.exports.grayscaleAndThreshold(clipImg, threshold, maxVal);
            // 回收裁剪图片
            clipImg.recycle();
            // 回收全屏图片
            img.recycle();
            // 返回处理后的图片
            return handlerImg;
        }
    },

    // 生成裁剪图片并保存到本地
    generateClipImgGrayThresholdToLocal(x1, y1, x2, y2, threshold, maxVal, localImageName, isOpenThreshold){
        // 裁剪图片并 灰度化阈值化 若不开启灰度化阈值化则仅返回裁剪图片
        let img = module.exports.generateClipImgGrayThreshold(x1, y1, x2, y2, threshold, maxVal, isOpenThreshold);
        // 本地图片路径
        let localImagePath = "/sdcard/autoJsLocalImg/";
        // 创建本地目录
        files.createWithDirs(localImagePath);
        // 保存到本地
        let fullPath = localImagePath + localImageName;
        images.save(img, fullPath, "png", 100);
        // 回收图片
        img.recycle();
        return fullPath;
    },

    // 远程处理操作
    remoteHandler(message){
        // 解密后字符串
        let decodeAftrJson = $base64.decode(message);
		console.log("远程处理消息：" + decodeAftrJson);
        try {
            let jsonObj = JSON.parse(decodeAftrJson);
            // 根据不同的操作类型进行处理
            if (jsonObj.type === "exec") {
                module.exports.remoteExecScript(jsonObj.data);
            } else if (jsonObj.type === "restart") {
                module.exports.remoteRestartScript(jsonObj.data);
            } else if (jsonObj.type === "upload") {
                module.exports.remoteUploadLogToServer(jsonObj.data);
            }
        } catch (error) {
            console.error("远程处理消息错误：", error);
        }
    },

    /**
     * 灰度化、阈值化多点找色
     * @desc 基于灰度化阈值化的多点找色
     * @param {Image} bigImg 大图对象
     * @param {int} threshold 阈值化相似度
     * @param {int} maxVal 阈值化最大值
     * @param {string} color 目标颜色值(第一个点的颜色值)
     * @param {Array} colorOther 其他颜色数组 例如：[[35, 30, "#FFFFFF"], [-28, -2, "#000000"], [-23, 20, "#000000"]]
     * @param {int} colorThreshold 颜色相似度
     * @returns {Object} 返回找色结果 images.findMultiColors的返回结果
     */
    grayThresholdFindMultipleColor(bigImg, threshold, maxVal, color, colorOther, colorThreshold) {
        // 大图 进行灰度化、阈值化处理 
        let bigImgAfter = this.grayscaleAndThreshold(bigImg, threshold, maxVal);
        // 调用官方多点找色方法
        let findResult = images.findMultiColors(bigImgAfter, color, colorOther, { threshold: colorThreshold });
        // 回收处理后的大图
        bigImgAfter.recycle()
        // 返回结果
        return findResult
    },

    /**
     * 灰度化、阈值化区域多点找色
     * @desc 在大图的区域坐标范围内,进行灰度化阈值化处理后,寻找匹配的多点颜色, 并返回基于大图的坐标
     * @param {Image} img 大图对象(一般为截全屏的图片对象)
     * @param {int} x1 区域坐标x1 
     * @param {int} y1 区域坐标y1
     * @param {int} x2 区域坐标x2
     * @param {int} y2 区域坐标y2
     * @param {int} threshold 阈值化相似度
     * @param {int} maxVal 阈值化最大值
     * @param {String} color 目标颜色值(第一个点的颜色值)
     * @param {Array} colorOther 其他颜色数组 例如：[[35, 30, "#FFFFFF"], [-28, -2, "#000000"], [-23, 20, "#000000"]]
     * @param  {int} colorThreshold 颜色相似度
     * @returns {x:int,y:int} 找色坐标对象
     */
    regionalFindMultipleColor(img, x1, y1, x2, y2, threshold, maxVal, color, colorOther, colorThreshold) {
        // 坐标转换
        let xy1 = this.convertXY(x1, y1)
        let xy2 = this.convertXY(x2, y2)
        // 按照区域坐标裁剪大图
        let clipImg = images.clip(img, xy1["x"], xy1["y"], xy2["x"] - xy1["x"], xy2["y"] - xy1["y"]);
        // 灰度化、阈值化多点找色
        let findResult = this.grayThresholdFindMultipleColor(clipImg, threshold, maxVal, color, colorOther, colorThreshold)
        // 回收裁剪图片
        clipImg.recycle()
        // 返回基于大图的坐标
        return {
            "x": findResult ? (xy1["x"] + findResult["x"]) : -1,
            "y": findResult ? (xy1["y"] + findResult["y"]) : -1
        }
    },

    /**
     * 灰度化、阈值化区域识别文字
     * @desc 在大图的区域坐标范围内,进行灰度化阈值化处理后 再进行文字识别
     * @param {Image} img 大图对象(一般为截全屏的图片对象)
     * @param {int} x1 区域坐标x1 
     * @param {int} y1 区域坐标y1
     * @param {int} x2 区域坐标x2
     * @param {int} y2 区域坐标y2
     * @param {int} threshold 阈值化相似度
     * @param {int} maxVal 阈值化最大值
     * @returns {Array} 文字识别内容
     */
    regionalAnalysisChart(img, x1, y1, x2, y2, threshold, maxVal) {
        // 坐标转换
        let xy1 = this.convertXY(x1, y1)
        let xy2 = this.convertXY(x2, y2)
        // 按照区域坐标裁剪大图
        let clipImg = images.clip(img, xy1["x"], xy1["y"], xy2["x"] - xy1["x"], xy2["y"] - xy1["y"]);
        // 灰度化、阈值化图片
        let imgAfter = this.grayscaleAndThreshold(clipImg, threshold, maxVal);
        // 回收裁剪图片
        clipImg.recycle();
        // 获取文字识别结果
        let resultStr = this.ocrGetContentStr(imgAfter)
        // 回收灰度化、阈值化后的图片
        imgAfter.recycle();
        return resultStr;
    },

    // OCR文字识别内容获取
    ocrGetContentStr(img) {
        try {
            // 使用Paddle进行OCR识别
            let results = this.ocr(img);
            return results.join('');
        } catch (error) {
            console.error("Paddle OCR识别错误:", error);
            return '';
        }
        return '';
    },

    // OCR根据内容获取位置
    ocrGetPositionByContent(img, matchingContent) {
        try {
            // 文字识别
            let results = this.ocrDetect(img);
            // 控制台是否打印识图结果
			let contentArr = results.map(item => item.label);
			console.info("OCR：" + contentArr.join(''));
            // 匹配目标orc对象
            let targetOcr = results.find(item => {
				return item.label && item.label.indexOf(matchingContent) !== -1
			});
            // 未匹配返回空
            if (!targetOcr) {
                return {
                    x: -1, y: -1
                };
            }
            // 获取边界框
            let boundingBox = targetOcr.bounds;
            if (boundingBox) {
                return {
                    x: boundingBox.centerX(),
                    y: boundingBox.centerY()
                };
            }
            return {
                x: -1, y: -1
            };
        } catch (error) {
            console.error("OCR获取位置错误:", error);
            return {
                x: -1, y: -1
            };
        }
     },

     /**
      * 灰度化、阈值化区域识别文字获取坐标
      * @desc 在大图的区域坐标范围内,进行灰度化阈值化处理后 再进行文字识别 寻找与目标内容匹配的坐标位置
      * @param {Image} img 大图对象(一般为截全屏的图片对象)
      * @param {int} x1 区域坐标x1 
      * @param {int} y1 区域坐标y1
      * @param {int} x2 区域坐标x2
      * @param {int} y2 区域坐标y2
      * @param {int} threshold 阈值化相似度
      * @param {int} maxVal 阈值化最大值
      * @param {String} matchingContent 匹配内容
      * @returns {x:int,y:int} 匹配文字的坐标
      */
     regionalAnalysisChartPostion(img, x1, y1, x2, y2, threshold, maxVal, matchingContent) {
         // 坐标转换
         let xy1 = this.convertXY(x1, y1)
         let xy2 = this.convertXY(x2, y2)
         // 按照区域坐标裁剪大图
         let clipImg = images.clip(img, xy1["x"], xy1["y"], xy2["x"] - xy1["x"], xy2["y"] - xy1["y"]);
         // 灰度化、阈值化图片
         let imgAfter = this.grayscaleAndThreshold(clipImg, threshold, maxVal);
         // 回收裁剪图片
         clipImg.recycle();

         // 根据内容获取匹配文字坐标
         let matchingPosition = this.ocrGetPositionByContent(imgAfter, matchingContent)

         // 回收灰度化、阈值化后的图片
         imgAfter.recycle();
         // 为找内容直接返回
         if (matchingPosition.x === -1) {
             return null
         }
         // 中心点x
         let centerX = xy1["x"] + matchingPosition.x
         // 中心点y
         let centerY = xy1["y"] + matchingPosition.y
         // 返回基于大图的坐标
         return {
             x: centerX, y: centerY
         }
     },

     // OCR结果绘制到Canvas
     ocrGetResultToCanvas(img) {
         // 读取
         let canvas = new Canvas(img);
         let rectanglePaint = new Paint();
         rectanglePaint.setStrokeWidth(3);
         rectanglePaint.setColor(colors.parseColor("#00ff00"));
         rectanglePaint.setStyle(Paint.Style.STROKE); //空心矩形框
         let textPaint = new Paint();
         textPaint.setTextAlign(Paint.Align.CENTER);
         textPaint.setTextSize(30);
         textPaint.setStyle(Paint.Style.FILL);
         textPaint.setColor(colors.parseColor("#f000ff"));
         let fontMetrics = textPaint.getFontMetrics();
         

         try {
             // 文字识别
             let results = this.ocrDetect(img);
             // 控制台是否打印识图结果
			let contentArr = results.map(item => item.label);
			console.info("【Paddle文字识别】：" + contentArr.join(''));
             results.forEach(item => {
                 let text = item.label;
                 if (text && item.location) {
                     let location = item.location;
                     let rect = [location[0][0], location[0][1], location[2][0], location[2][1]];
                     canvas.drawRect(rect[0], rect[1], rect[2], rect[3], rectanglePaint);
                     canvas.drawText(
                         text,
                         rect[0] + parseInt((rect[2] - rect[0]) / 2),
                         rect[3] + Math.abs(fontMetrics.top),
                         textPaint
                     );
                 } else if (text && item.bounds) {
                     let boundingBox = item.bounds;
                     canvas.drawRect(
                         boundingBox.left, 
                         boundingBox.top, 
                         boundingBox.right, 
                         boundingBox.bottom, 
                         rectanglePaint
                     );
                     canvas.drawText(
                         text,
                         boundingBox.centerX(),
                         boundingBox.bottom + Math.abs(fontMetrics.top),
                         textPaint
                     );
                 }
             });
         } catch (error) {
             console.error("OCR Canvas绘制错误:", error);
         }
         let image = canvas.toImage();
         return image;
     },

     /**
      * 灰度化、阈值化 区域识别文字并使用canvas生成图片保存到本地
      * @param {Image} img 大图对象(一般为截全屏的图片对象)
      * @param {int} x1 区域坐标x1 
      * @param {int} y1 区域坐标y1
      * @param {int} x2 区域坐标x2
      * @param {int} y2 区域坐标y2
      * @param {int} threshold 阈值化相似度
      * @param {int} maxVal 阈值化最大值
      * @param {String} localImageName 本地图片路径
      * @param {*} isOpenThreshold 是否开启灰度化、阈值化
      */
     regionalAnalysisChartToCanvasImg(img, x1, y1, x2, y2, threshold, maxVal, localImageName, isOpenThreshold) {
         // 坐标转换
         let xy1 = this.convertXY(x1, y1)
         let xy2 = this.convertXY(x2, y2)
         // 按照区域坐标裁剪大图
         let clipImg = images.clip(img, xy1["x"], xy1["y"], xy2["x"] - xy1["x"], xy2["y"] - xy1["y"]);
         // 处理图片
         let handlerImg
         // 开启灰度化、阈值化
         if (isOpenThreshold) {
             // 灰度化、阈值化图片
             handlerImg = this.grayscaleAndThreshold(clipImg, threshold, maxVal);
             // 回收裁剪图片
             clipImg.recycle();
             // 不开启 直接使用裁剪图片
         } else {
             handlerImg = clipImg;
         }

         // 返回img
         let canvasImg = this.ocrGetResultToCanvas(handlerImg);

         let newFilepath = "/sdcard/autoJsTools/analysisChart/" + localImageName;
         // 创建目录
         files.createWithDirs(newFilepath);
         // 保存canvas重绘图片
         images.save(canvasImg, newFilepath);
         // 回收图片
         canvasImg.recycle();
         // 回收图片
         handlerImg.recycle();
         // 返回新图片路径
         return newFilepath;
     },

     /**
      * 灰度化、阈值化 区域点击文字
      * @desc 在大图的区域坐标范围内,进行灰度化阈值化处理后 再进行文字识别 寻找与目标内容匹配的坐标位置 再点击坐标
       * @param {Image} img 大图对象(一般为截全屏的图片对象)
      * @param {int} x1 区域坐标x1 
      * @param {int} y1 区域坐标y1
      * @param {int} x2 区域坐标x2
      * @param {int} y2 区域坐标y2
      * @param {int} threshold 阈值化相似度
      * @param {int} maxVal 阈值化最大值
      * @param {String} matchingContent 匹配内容
      * @param {Function} successCall 成功回调
      */
     regionalClickText(img, x1, y1, x2, y2, threshold, maxVal, matchingContent, successCall, isClick) {
        if (typeof isClick === 'undefined') isClick = true;
         // 灰度化、阈值化区域识别文字获取坐标
         let macthingXy = this.regionalAnalysisChartPostion(img, x1, y1, x2, y2, threshold, maxVal, matchingContent)
         if (macthingXy) {
			if(isClick){
				this.randomClick(macthingXy.x, macthingXy.y, 1, false);
			}
             if (successCall) {
                 successCall(macthingXy)
             }
         }
     },

     /**
      * 初始化单选框组
      * @param {*} UIID ui组件id
      * @param {*} dataList 数据列表 {id:1,name:''}
      * @param {*} defaultCheckId 默认选中id
      * @param {*} checkCallback 选中回调事件
      */
     initRadioGroup(UIID, dataList, defaultCheckId, checkCallback) {
         if (!UIID || !dataList) {
             return
         }
         ui[UIID].removeAllViews();
         // 初始化单选框组数据
         dataList.forEach((item) => {
             let radioButton = new android.widget.RadioButton(context);
             let lp = new android.widget.RadioGroup.LayoutParams(android.widget.RadioGroup.LayoutParams.WRAP_CONTENT, android.widget.RadioGroup.LayoutParams.WRAP_CONTENT);
             // lp.setMargins(0,0,0,0);
             //radioButton.setPadding(0); // 设置文字距离按钮四周的距离
             radioButton.setId(item.id);//设置radiobutton的id
             radioButton.setText(item.name);
             //radioButton.setTextColor(android.R.drawable.textcolor_recharge_radiobutton);//字体颜色
             /*   if (item.id == defaultCheckId) {
                   // 初始化默认选中
                   radioButton.setChecked(true)
               } */
             ui[UIID].addView(radioButton, lp);
         })
         // 初始化checked事件
         this.radioGroupCheckedEvent(UIID, dataList, checkCallback);

         // 初始化默认选中
         ui[UIID].check(defaultCheckId)
         /* let needCheckButton = ui[UIID].findViewById(defaultCheckId);
         needCheckButton.setChecked(true); */
     },

     /**
      * 设置单选框change事件
      * @param {*} UIID ui的id
      * @param {*} dataList 数据列表
      * @param {*} callback 回调函数
      * @returns 
      */
     radioGroupCheckedEvent(UIID, dataList, callback) {
         if (!UIID) {
             return
         }
         dataMap[UIID] = dataList
         ui[UIID].setOnCheckedChangeListener(new android.widget.RadioGroup.OnCheckedChangeListener({
             onCheckedChanged: function (parent, checkedId) {
                 if (callback) {
                     //let buttonId = parent.getCheckedRadioButtonId()
                     //console.log(buttonId, checkedId)
                     // 获取id匹配的数据项
                     let data = dataList.find(item => item.id === checkedId)
                     let textContent = data ? data.name : ""
                     callback(textContent, parent, dataList, checkedId)
                 }
             }
         }))
     },

     /**
      * 初始化下拉框
      * @param {*} UIID ui组件id
      * @param {*} dataList 数据列表
      * @param {*} defaultSelectIndex 默认选中的数据索引(优先下标 小于0时根据defaultSelectItem取值)
      * @param {*} defaultSelectItem 默认选中数据项
      * @param {*} changeCallback 下拉框change回调
      * @returns 
      */
     initSelect(UIID, dataList, defaultSelectIndex, defaultSelectItem, changeCallback) {
         if (!UIID || !dataList) {
             return
         }
         // 初始化下拉框
         let adapter = new android.widget.ArrayAdapter(context, android.R.layout.simple_spinner_item, dataList);
         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
         ui[UIID].setAdapter(adapter);
         // 初始化change事件
         this.selectChangeEvent(UIID, dataList, changeCallback);
         // 初始化默认值
         let selectIndex = defaultSelectIndex && defaultSelectIndex > 0 ? defaultSelectIndex : (defaultSelectItem ? dataList.findIndex(item => item === defaultSelectItem) : -1)
         ui[UIID].setSelection(selectIndex)
     },

     /**
      * 下拉框change事件
      * @param {*} UIID Ui的id
      * @param {*} dataList 数据列表
      * @param {*} callback 回调函数
      * @returns 
      */
     selectChangeEvent(UIID, dataList, callback) {
         if (!UIID) {
             return
         }
         dataMap[UIID] = dataList
         ui[UIID].setOnItemSelectedListener(new android.widget.AdapterView.OnItemSelectedListener({
             onItemSelected: function (parent, view, position, id) {
                 if (callback) {
                     let textContent = parent.getItemAtPosition(position) || ui[UIID].getSelectedItem()
                     callback(textContent, parent, view, position, id, UIID)
                 }
             }
         }))
     },

     /**
      * 开关change事件
      * @param {*} UIID Ui的id
      * @param {*} callback 回调函数
      */
     switchChangeEvent(UIID, callback) {
         ui[UIID].on("check", function (checked) {
             callback(checked)
         });
     },

     /**
      * 设置UI缓存数据
      * @param {*} settingkeyArr UI设置key数组
      * @param {*} storageObj 储存对象
      */
     setUICacheData(settingkeyArr, storageObj) {
         settingkeyArr.forEach(item => {
             let key = item.key // key 
             let type = item.type // 类型
             let dataList = dataMap[key] || [] // 字典数据列表
             if (!ui[key]) {
                 return;
             }
             let value = ''
             switch (type) {
                 case "下拉框":
                     // 获取选中的内容
                     value = ui[key].getSelectedItem()
                     break;
                 case "单选框":
                     // 获取选中的id
                     let checkId = ui[key].getCheckedRadioButtonId()
                     // 数据
                     let data = dataList.find(item => item.id === checkId)
                     // 赋值
                     value = data ? data.name : ""
                     break;
                 case "开关":
                     value = ui[key].isChecked()
                     break;
                 case "输入框":
                     value = ui[key].getText()
                     break;
             }
             storageObj.put(key, value)
         })
     },

     /**
      * 获取UI缓存数据
      * @param {*} settingkeyArr  UI设置key数组
      * @param {*} storageObj 储存对象
      */
     getUICacheData(settingkeyArr, storageObj) {
         settingkeyArr.forEach(item => {
             let key = item.key // key
             let type = item.type // 类型
             let value = storageObj.get(key) || "" // 值
             let dataList = dataMap[key] || [] // 字典数据列表
             if (!ui[key]) {
                 return;
             }
             switch (type) {
                 case "下拉框":
                     // 获取数据项对应的下标
                     let selectIndex = dataList.findIndex(item => item === value)
                     // 根据下标设置选中项
                     ui[key].setSelection(selectIndex)
                     break;
                 case "单选框":
                     // 根据名称匹配数据
                     let data = dataList.find(item => item.name === value)
                     // 根据数据获取id
                     let checkId = data ? data.id : -1
                     // 初始化默认选中
                     ui[key].check(checkId)
                     break;
                 case "开关":
                     ui[key].setChecked(value || false)
                     break;
                 case "输入框":
                     ui[key].attr("text", value)
                     break;
             }

         })
     },

     // 图片点击功能
     clickImg(smallImgPath, threshold) {
         var smallImg = images.read(smallImgPath); //读取本地的领取图片
         var img = captureScreen();
         var result = findImage(img, smallImg, {
             threshold: threshold,
         }); //找到图会返回坐标 找不到返回null
         if (!result) {
             log("没找到");
             return false;
         } else {
             click(result.x, result.y);
             log("找到了");
             return true;
         }
     }
 };